/*
	Written By Pradipna Nepal
	www.pradsprojects.com

	Copyright (C) 2012 Prads Projects
	Please read COPYING.txt included along with this source code for more detail.
	If not included, see http://www.gnu.org/licenses/
*/

#include <iostream>
#include <vector>
#include <fstream>
#include "libTokenizer.h"
#include "libTokenModule.h"
#include "libSymbolTable.h"
#include "libPreProcessor.h"
#include "libParseModule.h"
#include "libCodeGeneration.h"
#include "tester.h"
using namespace std;
using namespace ModuleSeparator;
using namespace SymbolTable;
using namespace PreProcessor;
using namespace ParseModule;
using namespace CodeGenerator;
using namespace Tester;

bool saveBin(unsigned char *bin, const char *path);

int main(int argc, char **argv) {
	cout << "Chip16 compiler written by Pradipna Nepal and Sanjay Giri...\r\n\r\n";
	if (argc < 3) {
		cout << "Not enough arguments...\r\n";
		return 0;
	}

	cout << "Tokenizing...\r\n";
	vector<Token> tokens;
	Tokenizer tokenizer(argv[1]);
	tokens = tokenizer.tokenize();

	vector<TokenModule> tokenModule;
	cout << "OK\r\nSeparating Token into Token Modules...\r\n";
	if (tokens.size() != 0) {
		if (!separateModules(&tokens, &tokenModule)) goto error;
		cout << "OK\r\nCreating Symbol Table...\r\n";
		SblTable symbolTable;

		if (!createSymbolTable(&tokenModule, &symbolTable)) goto error;
		
		cout << "OK\r\nPreprocessing...\r\n";
		if (!handleConst(&symbolTable.identTable, &tokenModule)) goto error;
		
		cout << "OK\r\nParsing Token Modules...\r\n";
		vector<list<Opcode>> ir;
		if (!parseModule(&tokenModule, &ir, &symbolTable)) goto error;
		
		cout << "OK\r\nGenerating Code...\r\n";
		string patcherCommand;
		unsigned char bin[0xFFFF];
		memset(bin, 0, 0xFFFF);
		int pathEnd = 0;
		string path = string(), fullPath = argv[1];
		for (int i = fullPath.size() - 1; i > 0; --i) {
			if (fullPath[i] == '/') {
				pathEnd = i;
				break;
			}
		}
		for (int i = 0; i < pathEnd; ++i) path += fullPath[i];
		if (pathEnd > 0) path += "/";
		generateCode(&tokenModule, &symbolTable, &ir, bin, &patcherCommand, path.c_str());

		cout << "OK\r\n";
		path += argv[2];
		saveBin(bin, path.c_str());
		
		cout << "Patching ROM for adding Header...\r\n";
		patcherCommand = "headerPatcher.exe " + path + " -o " + path + " -v 1.1 -s " + patcherCommand;
		system(patcherCommand.c_str());
		cout << "OK\r\n";
	} else {
error:
		cout << "FAILED\r\n";
	}
	
	cout << "Done...\r\n";
	return 0;
}

bool saveBin(unsigned char *bin, const char *path) {
	cout << "Creating Binary File...\r\n";
	ofstream binFile;

	binFile.open(path, ios::binary);
	if (binFile.is_open()) {
		binFile.write((char*)bin, 0xFFFF);
		binFile.close();
	} else {
		cout << "FAILED\r\n";
		return false;
	}
	cout << "OK\r\n";
	return true;
}